package collection;

import java.util.Arrays;
import java.util.Objects;

/**
 * 自定义的ArrayList实现类，用于存储任意类型的对象
 * 它允许动态调整数组大小以适应更多元素的存储需求
 *
 * @param <T> 泛型参数，表示此列表可以存储的类型
 */
public class MyArrayList<T> {
    // 存储元素的数组
    private Object[] array;
    // 当前列表中元素的数量
    private int size;

    // 默认的数组容量
    private static final int DEFAULT_SIZE = 10;
    // 数组扩容的倍数
    private static final double MULTIPLE = 1.5;

    /**
     * 默认构造函数，使用默认容量初始化数组
     */
    public MyArrayList() {
        this(DEFAULT_SIZE);
    }

    /**
     * 构造函数，允许指定初始容量
     *
     * @param capacity 初始容量，决定了数组的初始大小
     */
    public MyArrayList(int capacity) {
        array = new Object[capacity];
        size = 0;
    }

    /**
     * 检查列表是否为空
     *
     * @return 如果列表为空，则返回true；否则返回false
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 检查列表是否已满
     *
     * @return 如果列表已满，则返回true；否则返回false
     */
    public boolean isFull() {
        return size == array.length;
    }

    /**
     * 在列表末尾添加一个元素
     *
     * @param element 要添加的元素
     */
    public void add(T element) {
        add(size, element);
    }

    /**
     * 在指定位置插入一个元素
     * 如果当前位置已有元素，则会将当前位置及之后的元素向后移动以腾出空间
     * 如果数组已满，则会自动扩容
     *
     * @param pos    插入位置的索引
     * @param element 要插入的元素
     */
    public void add(int pos, T element) {
        if (isFull()) {
            resize((int) (array.length * MULTIPLE));
        }

        if (pos > size || pos < 0) {
            throw new IndexOutOfBoundsException("越界异常");
        }

        for (int i = size - 1; i >= pos; i--) {
            array[i + 1] = array[i];
        }

        array[pos] = element;
        size++;
    }

    /**
     * 替换指定位置的元素
     *
     * @param pos    要替换的元素的位置
     * @param element 新的元素
     */
    public void set(int pos, T element) {
        if (pos >= size || pos < 0) {
            throw new IndexOutOfBoundsException("越界异常");
        }
        array[pos] = element;
    }

    /**
     * 清空列表中的所有元素
     * 为了防止内存泄漏，会将数组中的每个元素设置为null
     */
    public void clear() {
        Arrays.fill(array, null);
        size = 0;
    }

    /**
     * 获取指定位置的元素
     *
     * @param pos 要获取的元素的位置
     * @return 位于指定位置的元素
     */
    public Object get(int pos) {
        if (pos >= size || pos < 0) {
            throw new IndexOutOfBoundsException("越界异常");
        }
        return array[pos];
    }

    /**
     * 查找元素在列表中的索引位置
     * 如果元素不存在于列表中，则返回-1
     *
     * @param element 要查找的元素
     * @return 元素的索引位置，如果未找到则返回-1
     */
    public int indexOf(T element) {
        for (int i = 0; i < size; i++) {
            if (Objects.equals(array[i], element)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 从列表中移除指定元素
     * 如果元素存在，此方法将移除第一个匹配的元素
     *
     * @param element 要移除的元素
     */
    public void remove(T element) {
        int index = indexOf(element);
        if (index != -1) {
            remove(index);
        }
    }

    /**
     * 从列表中移除指定位置的元素
     *
     * @param pos 要移除的元素的位置
     */
    public void remove(int pos) {
        if (pos >= size || pos < 0) {
            throw new IndexOutOfBoundsException("越界异常");
        }
        for (int i = pos; i < size - 1; i++) {
            array[i] = array[i + 1];
        }
        size--;
        array[size] = null; // 清空最后一个位置以防止内存泄漏
    }

    /**
     * 检查列表是否包含指定元素
     *
     * @param element 要检查的元素
     * @return 如果列表包含指定元素，则返回true；否则返回false
     */
    public boolean contains(T element) {
        return indexOf(element) != -1;
    }

    /**
     * 调整数组大小以适应新的容量需求
     * 此方法解释了为什么需要调整数组大小：当当前数组容量不足以存储更多元素时，通过调用此方法可以扩大数组容量，
     * 确保数组能够存储更多的元素而不丢失原有数据
     *
     * @param newCapacity 新的数组容量，这是调整数组大小的必要参数，因为它指定了目标容量大小
     */
    private void resize(int newCapacity) {
        array = Arrays.copyOf(array, newCapacity);
    }
}
